package cliu.TutorialOnImages;

/*
 * TutorialOnImages.java
 * 
 * [AUTHOR]: Chunyen Liu
 * [SDK   ]: Android SDK 2.1 and up
 * [NOTE  ]: http://www.developer.com/ws/other/article.php/3748281/Working-with-Images-in-Googles-Android.htm
 */

import java.io.File;
import java.io.FileOutputStream;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.Toast;

public class TutorialOnImages extends Activity {
	private MyImageView mIV;
	private Bitmap mBitmap;
	private int mPhotoWidth = 0;
	private int mPhotoHeight = 0;    

	@Override
	public void onCreate(Bundle icicle) {
		super.onCreate(icicle); 

		mIV = new MyImageView(this);
		setContentView(mIV);       

		mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.clive);             
		mPhotoWidth = mBitmap.getWidth();
		mPhotoHeight = mBitmap.getHeight();        

		mIV.setImageBitmap(mBitmap); 
		mIV.invalidate();
	}

	// Implement the tinting algorithm
	private void TintThePicture(int deg) {
		int[] pix = new int[mPhotoWidth * mPhotoHeight];
		mBitmap.getPixels(pix, 0, mPhotoWidth, 0, 0, mPhotoWidth, mPhotoHeight);
        
		double angle = (3.14159d * (double)deg) / 180.0d;	        
		int S = (int)(256.0d * Math.sin(angle));	        
		int C = (int)(256.0d * Math.cos(angle));

		int r, g, b, index;
		int RY, BY, RYY, GYY, BYY, R, G, B, Y;	
		
		for (int y = 0; y < mPhotoHeight; y++) {	    
			for (int x = 0; x < mPhotoWidth; x++) {	    	    	
				index = y * mPhotoWidth + x;	    	    	
				r = (pix[index] >> 16) & 0xff;	    
				g = (pix[index] >> 8) & 0xff;	    	    	
				b = pix[index] & 0xff;	    	    	
				RY = (70 * r - 59 * g - 11 * b) / 100;	    	    	
				BY = (-30 * r - 59 * g + 89 * b) / 100;	    	    	
				Y = (30 * r + 59 * g + 11 * b) / 100; 	        	
				RYY = (S * BY + C * RY) / 256;	    	    	
				BYY = (C * BY - S * RY) / 256;	    	    	
				GYY = (-51 * RYY - 19 * BYY) / 100;	    	    	
				R = Y + RYY;	    	    	
				R = (R < 0) ? 0 : ((R > 255) ? 255 : R);	    	    	
				G = Y + GYY;	    	    	
				G = (G < 0) ? 0 : ((G > 255) ? 255 : G);	    	    	
				B = Y + BYY;	    	    	
				B = (B < 0) ? 0 : ((B > 255) ? 255 : B);	   	    	
				pix[index] = 0xff000000 | (R << 16) | (G << 8) | B;   	    		
			}
		}

		Bitmap bm = Bitmap.createBitmap(mPhotoWidth, mPhotoHeight, Bitmap.Config.ARGB_8888);
		bm.setPixels(pix, 0, mPhotoWidth, 0, 0, mPhotoWidth, mPhotoHeight); 	

		if (null != mBitmap) {
			mBitmap.recycle();
		}
		mBitmap = bm;

		// Put the updated bitmap into the main view
		mIV.setImageBitmap(mBitmap);	
		mIV.invalidate();

		pix = null;
	}

	// Save the result onto a file on SD card
	private void SaveThePicture() {
		// Make sure the folder is available on SD card
		String dirname = Environment.getExternalStorageDirectory() + "/tutorialonimages/";
		File sddir = new File(dirname);
		if (!sddir.mkdirs()) {
			if (sddir.exists()) {
			} else {
				Toast.makeText(TutorialOnImages.this, "Folder error",
						Toast.LENGTH_SHORT).show();
				return;
			}
		}

		// Save the image
		try { 
			FileOutputStream fos = new FileOutputStream(dirname + "output.jpg"); 	 
			mBitmap.compress(CompressFormat.JPEG, 75, fos);

			fos.flush();	           
			fos.close();	           
		} catch (Exception e) {	        
			Log.e("MyLog", e.toString());	           
		} 	    
	}       

	static int switch_i = 1;
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {	
		case MotionEvent.ACTION_UP: 
			
			// Tint image
			// doImageTint();
			if(switch_i==1) {
				//doCannyEdge();
				mIV.setImageBitmap(extractSkinColor(mBitmap));
				mIV.invalidate();
				switch_i = 0;
			} else {
				mIV.setImageBitmap(mBitmap);
				mIV.invalidate();
				switch_i = 1;
			}
			
			return (true);
		case MotionEvent.ACTION_DOWN:                
			break;
		}

		return super.onTouchEvent(event);
	}  
	
	private Bitmap extractSkinColor(Bitmap sourceImage) {
		int width = sourceImage.getWidth();
		int height = sourceImage.getHeight();
		Bitmap bmpSkin = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
		int color = 0;
		float[] hsv = {0f, 0f, 0f};
		for(int x=0; x<width; x++){
			for(int y=0; y<height; y++){
				color = sourceImage.getPixel(x, y);				
				Color.colorToHSV(color, hsv);
				if ((hsv[0]<60 && hsv[1]>0.5 && hsv[2]>0.5)){ // not red to yellow color
					bmpSkin.setPixel(x, y, Color.rgb(255,255,255));// original color Color.HSVToColor(hsv));
				}
				else
				{
					bmpSkin.setPixel(x, y, Color.rgb(0, 0, 0));
				}
			}
		}
		return bmpSkin;
	}
	
	private Bitmap toGrayScale(Bitmap sourceImage) {
		int width, height;
		width = sourceImage.getWidth();
		height = sourceImage.getHeight();
		Bitmap bmpGray = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
		Canvas c = new Canvas(bmpGray);
		Paint paint = new Paint();
		ColorMatrix cm = new ColorMatrix();
		cm.setSaturation(0);
		ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
		paint.setColorFilter(f);
		c.drawBitmap(sourceImage, 0, 0, paint);
		return bmpGray;
	}
	
	private void doCannyEdge() {
		CannyEdgeDetector edge= new CannyEdgeDetector();
		edge.setSourceImage(extractSkinColor(mBitmap));
		edge.setLowThreshold(0.5f);
		edge.setHighThreshold(1f);
		edge.process();
		mIV.setImageBitmap(edge.getEdgesImage());
		mIV.invalidate();
	}
	
	private void doImageTint() {
		// Perform the tinting operation
		TintThePicture(60);	

		// Display a short message on screen
		Toast.makeText(TutorialOnImages.this, "Picture was tinted", Toast.LENGTH_SHORT).show();

		// Save the result
		SaveThePicture();	
	}
}
